package com.ling.pl.security.utils;

import com.ling.pl.core.cache.ApplicationCache;
import com.ling.pl.security.model.DefaultRole;
import com.ling.pl.security.model.DefaultUser;
import com.ling.pl.security.model.RoleMember;
import com.ling.pl.security.model.UrlComponent;
import com.ling.pl.security.service.DefaultRoleService;
import com.ling.pl.security.service.DefaultUrlService;
import com.ling.pl.security.service.DefaultUserService;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.*;

/**
 * @author bo.wang
 */
@Component(ComponentMetadataSource.BEAN_ID)
public class ComponentMetadataSource {
    public static final String BEAN_ID = "ling2.componentMetadataSource";
    @Resource
    DefaultUserService userService;
    private String componentMetadataCacheKey = "component_metadata_";
    @Resource
    private ApplicationCache applicationCache;
    @Resource
    private DefaultRoleService roleService;
    @Resource
    private DefaultUrlService urlService;

    public Collection<ConfigAttribute> getAttributes(String urlComponentId, DefaultUser authentication)
            throws IllegalArgumentException {
        Map<String, Collection<Map<String, Collection<ConfigAttribute>>>> metadata = getMetadata();
        String orgCompanyId = authentication.getCompanyId();
        Collection<Map<String, Collection<ConfigAttribute>>> attributeMaps = null;
        String[] companyIds = orgCompanyId.split(",");
        for (String companyId : companyIds) {
            attributeMaps = metadata.get(companyId);
            if (attributeMaps != null) break;
        }
        if (attributeMaps == null) {
            return null;
        }
        Collection<ConfigAttribute> attributes = null;
        for (Map<String, Collection<ConfigAttribute>> map : attributeMaps) {
            if (map.containsKey(urlComponentId)) {
                attributes = map.get(urlComponentId);
                break;
            }
        }
        Collection<ConfigAttribute> attributesResult = new ArrayList<ConfigAttribute>();
        if (attributes == null) {
            return attributesResult;
        }
        return attributes;
    }

    @SuppressWarnings("unchecked")
    private Map<String, Collection<Map<String, Collection<ConfigAttribute>>>> getMetadata() {
        Map<String, Collection<Map<String, Collection<ConfigAttribute>>>> metadata = (Map<String, Collection<Map<String, Collection<ConfigAttribute>>>>) applicationCache.getCacheObject(componentMetadataCacheKey);
        if (metadata == null) {
            initComponentMetadata();
            metadata = (Map<String, Collection<Map<String, Collection<ConfigAttribute>>>>) applicationCache.getCacheObject(componentMetadataCacheKey);
        }
        return metadata;
    }

    public void initComponentMetadata() {
        /**
         * metadata这个map中key为companyId,value是一Collection,这个collection中的map的key为url+|+componentId,value为SecurityConfigAttribute集合
         * */
        Map<String, Collection<Map<String, Collection<SecurityConfigAttribute>>>> metadata = new HashMap<String, Collection<Map<String, Collection<SecurityConfigAttribute>>>>();
        for (DefaultRole role : roleService.loadAllRoles()) {
            role.setRoleMembers(roleService.loadRoleMemberByRoleId(role.getId()));
            role.setUrlComponents(urlService.loadComponentUrlsByRoleId(role.getId()));

            String companyId = role.getCompanyId();
            Collection<Map<String, Collection<SecurityConfigAttribute>>> urlComponentAttributes = null;
            if (!metadata.containsKey(companyId)) {
                urlComponentAttributes = new ArrayList<Map<String, Collection<SecurityConfigAttribute>>>();
                metadata.put(companyId, urlComponentAttributes);
            } else {
                urlComponentAttributes = metadata.get(companyId);
            }
            for (UrlComponent uc : role.getUrlComponents()) {
                Collection<SecurityConfigAttribute> SecurityConfigAttributes = this.buildSecurityConfigAttributes(role.getRoleMembers(), uc, role.getCompanyId());
                String targetUrl = uc.getUrl().getUrl();
                targetUrl = ((targetUrl == null) ? "" : targetUrl);
                String urlCmoponentId = targetUrl + "|" + uc.getComponent().getComponentId() + "|" + uc.getAuthorityType().toString();
                Collection<SecurityConfigAttribute> attributes = null;

                for (Map<String, Collection<SecurityConfigAttribute>> map : urlComponentAttributes) {
                    if (map.containsKey(urlCmoponentId)) {
                        attributes = map.get(urlCmoponentId);
                        break;
                    }
                }
                if (attributes == null) {
                    attributes = SecurityConfigAttributes;
                    Map<String, Collection<SecurityConfigAttribute>> map = new HashMap<String, Collection<SecurityConfigAttribute>>();
                    map.put(urlCmoponentId, attributes);
                    urlComponentAttributes.add(map);
                } else {
                    attributes.addAll(SecurityConfigAttributes);
                }
            }
        }
        applicationCache.putCacheObject(componentMetadataCacheKey, metadata);
    }

    private Collection<SecurityConfigAttribute> buildSecurityConfigAttributes(List<RoleMember> members, UrlComponent uc, String companyId) {
        Collection<SecurityConfigAttribute> attributes = new ArrayList<SecurityConfigAttribute>();
        for (RoleMember member : members) {
            AttributeType type = null;
            Object obj = null;
            if (member.getUser() != null) {
                type = AttributeType.user;
                obj = member.getUser();
            }
            if (member.getOrg() != null) {
                type = AttributeType.org;
                obj = member.getOrg();
            }
            if (member.getPosition() != null) {
                type = AttributeType.position;
                obj = member.getPosition();
            }
            if (member.getGroup() != null) {
                type = AttributeType.group;
                obj = member.getGroup();
            }
            SecurityConfigAttribute att = new SecurityConfigAttribute(type, member.isGranted(), companyId);
            att.setMember(obj);
            attributes.add(att);
        }
        return attributes;
    }
}
